package user.service.Impl;

import com.alibaba.fastjson.JSON;
import com.spring4all.spring.boot.starter.hbase.api.HbaseTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import user.contstant.Constants;
import user.mapper.PassTemplateRowMapper;
import user.service.IGainPassTemplateService;
import user.util.RowKeyGenUtil;
import user.vo.GainPassTemplateRequest;
import user.vo.PassTemplate;
import user.vo.Response;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 用户领取优惠券功能实现
 */
@Slf4j
@Service
public class GainPassTemplateServiceImpl implements IGainPassTemplateService {

    //HBase客户端
    private final HbaseTemplate hbaseTemplate;
    //redis客户端
    private final StringRedisTemplate stringRedisTemplate;

    @Autowired
    public GainPassTemplateServiceImpl(HbaseTemplate hbaseTemplate,
                                       StringRedisTemplate stringRedisTemplate) {
        this.hbaseTemplate = hbaseTemplate;
        this.stringRedisTemplate = stringRedisTemplate;
    }
    /**
    * 用户领取优惠券
    * @param request {@link GainPassTemplateRequest}
    * @return {@link Response}
    * @throws Exception
    @Override
    */
    public Response gainPassTemplate(GainPassTemplateRequest request) throws Exception {

        PassTemplate passTemplate;
        String passTemplateId = RowKeyGenUtil.genPassTemplateRowKey(
                    request.getPassTemplate());

        //获取passTemplate
        try{
            passTemplate = hbaseTemplate.get(
                    Constants.PassTemplateTable.TABLE_NAME,
                    passTemplateId,
                    new PassTemplateRowMapper()
            );
        }catch (Exception e){
            log.error("gain passTemplate error:{}", JSON.toJSONString(request.getPassTemplate()));
            return Response.failure("gian passTemplate error");
        }
        //判断个数限制是否可领取
        if(passTemplate.getLimit() < 1 && passTemplate.getLimit() != -1){
            log.error("passTemplate limit max :{}",JSON.toJSONString(request.getPassTemplate()));
            return Response.failure("passTemplate limit max!");
        }

        //判断是否在日期内
        Date cur = new Date();
        if(!(cur.getTime() >= passTemplate.getStart().getTime()
                && cur.getTime() < passTemplate.getEnd().getTime())){
            log.error("passTemplate validTime error:{}",JSON.toJSONString(request.getPassTemplate()));
            return Response.failure("passTemplate validTime error");
        }

        //减去优惠券的limit
        if(passTemplate.getLimit() != -1){
            List<Mutation> datas = new ArrayList<>();
            byte[] FAMILY_C = Constants.PassTemplateTable.FAMILY_C.getBytes();
            byte[] LIMIT = Constants.PassTemplateTable.LIMIT.getBytes();

            //修改
            Put put = new Put(Bytes.toBytes(passTemplateId));
            put.addColumn(FAMILY_C,LIMIT,Bytes.toBytes(passTemplate.getLimit()-1));
            datas.add(put);

            //保存
            hbaseTemplate.saveOrUpdate(Constants.PassTemplateTable.TABLE_NAME, (Mutation) datas);

            //将优惠券保存到用户优惠券表
            if(!addPassForUser(request,passTemplate.getId(),passTemplateId)){
                return Response.failure("gainPassTemplate failure");
            }
        }
        return Response.success();
    }

    /**
     *  给用户添加优惠券
     * @param request {@link GainPassTemplateRequest}
     * @param merchantsId 商户id
     * @param passTemplateId 优惠券id
     * @return true/false
     */
    private boolean addPassForUser(GainPassTemplateRequest request,
                                   Integer merchantsId,
                                   String passTemplateId) throws Exception{

        byte[] FAMILY_I = Constants.PassTable.FAMILY_I.getBytes();
        byte[] USER_ID = Constants.PassTable.USER_ID.getBytes();
        byte[] TEMPLATE_ID = Constants.PassTable.TEMPLATE_ID.getBytes();
        byte[] TOKEN = Constants.PassTable.TOKEN.getBytes();
        byte[] ASSIGNED_DATE = Constants.PassTable.ASSIGNED_DATE.getBytes();
        byte[] CON_DATE = Constants.PassTable.CON_DATE.getBytes();

        /**填充数据*/
        List<Mutation> datas = new ArrayList<>();
        Put put = new Put(Bytes.toBytes(RowKeyGenUtil.genPassRowKey(request)));
        put.addColumn(FAMILY_I,USER_ID,Bytes.toBytes(request.getUserId()));
        put.addColumn(FAMILY_I,TEMPLATE_ID,Bytes.toBytes(passTemplateId));

        //判断是否拥有token
        if(request.getPassTemplate().getHasToken()){
            String token = stringRedisTemplate.opsForSet().pop(passTemplateId);
            //如果为空
            if(token == null){
                log.error("token not exist:{}",passTemplateId);
                return false;
            }
            //不为空则写入文件
            recordTokenToFile(merchantsId,passTemplateId,token);
            put.addColumn(FAMILY_I,TOKEN,Bytes.toBytes(token));
        }else {
            put.addColumn(FAMILY_I,TOKEN,Bytes.toBytes("-1"));
        }
        put.addColumn(FAMILY_I,ASSIGNED_DATE,Bytes.toBytes(DateFormatUtils.ISO_DATE_FORMAT.format(new Date())));
        put.addColumn(FAMILY_I,CON_DATE,Bytes.toBytes("-1"));

        datas.add(put);
        //写入HBase
        hbaseTemplate.saveOrUpdate(Constants.PassTable.TABLE_NAME, (Mutation) datas);
        return true;
    }
    /**
     * 将已使用的token记录到文件中
     * @param merchantsId 商户id
     * @param passTemplateId 优惠券id
     * @param token 分配的优惠券token
     */
    private void recordTokenToFile(Integer merchantsId, String passTemplateId, String token)
            throws Exception{

        Files.write(
                Paths.get(Constants.TOKEN_DIR,String.valueOf(merchantsId),
                        passTemplateId + Constants.USED_TOKEN_SUFFIX),
                        (token + "\n").getBytes(),
                        StandardOpenOption.APPEND
        );
    }
}
